use crate::{bootstrap::AppState, router::resp::RespVO, service};
use axum::{
    body::Body,
    extract::{Path, Query, State},
    http::Response,
    response::IntoResponse,
};
use chrono::Duration;
use redis::{AsyncCommands, RedisError};
use serde_json::json;
use sky_pojo::{
    dto::{self, dish::DishFlavorDTO},
    vo::dish::{DishItemVO, DishVO},
};

pub async fn get_dishes_from_cache(
    redis: &mut redis::aio::MultiplexedConnection,
    key: &str,
) -> Result<Vec<DishVO>, Box<dyn std::error::Error>> {
    let data: Option<String> = match redis.get(key).await {
        Ok(val) => val,
        Err(e) => return Err(Box::new(e)),
    };

    if let Some(json) = data {
        let dishes: Vec<DishVO> = match serde_json::from_str(&json) {
            Ok(val) => val,
            Err(e) => return Err(Box::new(e)),
        };
        Ok(dishes)
    } else {
        Ok(Vec::new())
    }
}

pub async fn list(
    State(mut state): State<AppState>,
    Query(dto): Query<DishFlavorDTO>,
) -> Response<Body> {
    let key = format!("dish_{}", dto.category_id);
    // 先尝试从 Redis 获取数据
    let dishes = match get_dishes_from_cache(&mut state.redis, &key).await {
        Ok(dishes) => {
            tracing::info!("Fetched dishes from Redis: {:?}", dishes);
            Some(dishes)
        }
        Err(e) => {
            tracing::error!("Failed to get dishes from Redis: {}", e);
            // 可以考虑重试或其他策略，这里只是简单记录日志
            None
        }
    };

    if let Some(dishes) = dishes {
        if !dishes.is_empty() {
            return RespVO::<Vec<DishVO>>::success("success".to_owned(), Some(dishes))
                .into_response();
        }
    }

    // 如果缓存中没有数据，查询数据库
    let result = service::dish::list_with_flaovr(state.db_pool, dto).await;

    match result {
        Ok(dish_vec) => {
            // 成功查询到数据库结果，更新 Redis 缓存
            let json = match serde_json::to_string(&dish_vec) {
                Ok(json_data) => json_data,
                Err(e) => {
                    tracing::error!("Failed to serialize dish vector: {}", e);
                    return RespVO::<Vec<DishVO>>::error_without_data("Internal error".to_owned())
                        .into_response();
                }
            };

            // 更新 Redis 缓存并设置过期时间
            match state
                .redis
                .set_ex::<String, String, ()>(
                    key.clone(),
                    json,
                    Duration::minutes(10).num_seconds().try_into().unwrap(),
                )
                .await
            {
                Ok(_) => tracing::info!("Successfully updated Redis cache for key: {}", key),
                Err(e) => tracing::error!("Failed to set Redis cache: {}", e),
            }

            // 返回查询结果
            RespVO::<Vec<DishVO>>::success("success".to_owned(), Some(dish_vec)).into_response()
        }
        Err(e) => {
            tracing::error!("Failed to query dishes from DB: {}", e);
            RespVO::<()>::error_without_data(e.to_string()).into_response()
        }
    }
}
